#include <iostream>		// cout
#include <cmath>		// NAN

#include <Module-Data/DataAccess.hpp>

//#include <QtGui>
#include "ui_gps.h"
#include "AppWin.hpp"

using namespace std;
using namespace ModuleData;
using namespace Ui;

AppWin *pwin;
extern float current_x, current_y;

struct Date
{
  int year;
  int month;
  int date;
  Date( const char *str )	// ddmmyy
  {
    date = (*str-'0')*10+(*(str+1)-'0');
    str += 2;
    month = (*str-'0')*10+(*(str+1)-'0');
    str += 2;
    year = (*str-'0')*10+(*(str+1)-'0') + 2000; // 凑合着用吧……
  }
private:
  Date();
};

struct UTCtime
{
  int hour;
  int minute;
  int second;
  int m_second;
  UTCtime( const char *str )	// hhmmss.xx
  {
    hour = (*str-'0')*10+(*(str+1)-'0');
    str += 2;
    minute = (*str-'0')*10+(*(str+1)-'0');
    str += 2;
    second = (*str-'0')*10+(*(str+1)-'0');
    str += 3;
    m_second = (*str-'0')*100+(*(str+1)-'0')*10;
  }
private:
  UTCtime();
};

void* general( int type, const char *info )
{
  void *ret_val;
  UTCtime *timep;
  Date *datep;
  float lat, lon;
  char  pos;
  int got_count;

  switch( type )
    {
    case RMC_UTC:
      timep = new UTCtime( info );
      ret_val = reinterpret_cast<void*>( timep );
      break;

    case RMC_DATE:
      datep = new Date( info );
      ret_val = reinterpret_cast<void*>( datep );
      break;

    case RMC_LATITUDE:
      got_count = sscanf( info, "%f,%c", &lat, &pos );
      if( got_count < 2 )
	{
	  lat = NAN;
	}
      else
	{
	  lat = pos == 'N'? lat:-lat;
	}
      ret_val = reinterpret_cast<void*&>( lat );
      break;

    case RMC_LONGITUDE:
      got_count = sscanf( info, "%f,%c", &lon, &pos );
      if( got_count < 2 )
	{
	  lon = NAN;
	}
      else
	{
	  lon = pos == 'E'? lon:-lon;
	}
      ret_val = reinterpret_cast<void*&>( lon );
      break;

    default:
      string *strp = new string( info );
      ret_val = reinterpret_cast<void*>( strp );
    }

  return ret_val;
}

void deconstruct( int type, void *obj_addr )
{
  UTCtime *pt;
  Date *pd;
  string *ps; 

  switch( type )
    {
    case RMC_UTC:
      pt = static_cast<UTCtime*>( obj_addr );
      delete pt;
      break;
    case RMC_DATE:
      pd = static_cast<Date*>( obj_addr );
      delete pd;
      break;
    case RMC_LATITUDE:
      break;
    case RMC_LONGITUDE:
      break;
    default:
      ps = static_cast<string*>( obj_addr );
      delete ps;
    }
}

void check_run( void )
{
  const GPSdata &pdata = ModuleData::instance().get_last_data();
  if( pdata.get_type() != GPS_SENTENCE_GPRMC )
    {
      return;
    }

  //  UTCtime *pt = static_cast<UTCtime*>( pdata.get_value( RMC_UTC ) );
  //  Date *pd = static_cast<Date*>( pdata.get_value( RMC_DATE ) );
  float la, lo;
  void *p = pdata.get_value( RMC_LATITUDE );
  la = reinterpret_cast<float&>( p );
  p = pdata.get_value( RMC_LONGITUDE );
  lo = reinterpret_cast<float&>( p );

  if( isnan( la ) || isnan( lo ) )
    {
      return;
    }

  if( la != current_x || lo != current_y )
    {
      current_x = la;
      current_y = lo;
      pwin->post_reload();
      usleep( 50*1000 );	// 让出cpu
    }

  //  cout << "Current Time:" << pt->hour << ':' << pt->minute << ':' << pt->second << '.' << pt->m_second << endl;
  //  cout << "Current Date:" << pd->year << '-' << pd->month << '-' << pd->date << endl;
  //  cout << "Current Location:" << la << "  +  " << lo << endl;
  //  cout << "<<<<<<<<<<>>>>>>>>>>" << endl;
}

int main( int argc, char *argv[])
{
  // 设置default_gen和default_del
  ModuleData::default_gen = general;
  ModuleData::default_del = deconstruct;

  ModuleData::instance().add_listener( GPS_RECEIVER_DATA_RECEIVE, check_run );

  QApplication app( argc, argv );
  AppWin       win;

  QObject::connect( &app, SIGNAL( lastWindowClosed() ), &app, SLOT( quit() ));

  pwin = &win;
  ModuleData::instance().monitor();

  win.show();
  app.exec();

  return 0;
}
